package com.project.common.core.utils.weChat;

import com.project.common.core.config.prop.PropAttributes;
import com.project.common.core.config.prop.PropConfig;
import com.project.common.core.utils.HttpUtil;
import com.project.common.core.utils.JacksonUtil;
import com.project.common.core.utils.SpringUtils;
import com.project.common.core.utils.file.FilePathConsts;
import com.project.common.core.utils.exception.BASE_RESP_CODE_ENUM;
import com.project.common.core.utils.exception.BaseCustomException;
import com.project.common.core.utils.redis.RedisClient;
import com.project.common.core.utils.redis.RedisConsts;
import com.project.common.core.utils.wx.message.res.TemplateMessage;
import com.project.common.core.utils.wx.pojo.AccessToken;
import com.project.common.core.utils.wx.pojo.WeChat;
import com.project.common.core.utils.wx.pojo.qrcode.*;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 微信工具类
 *
 * @author WYY
 * @date 2018/1/3
 */
public final class WeChatUtil {
    /**
     * 日志对象
     */
    private static final Logger log = LoggerFactory.getLogger(WeChatUtil.class);

    /**
     * Redis客户端
     */
    private static RedisClient REDIS_CLIENT = null;

    /**
     * 微信网页授权地址【用户信息授权地址】
     */
    public static final String USERINFO_WX_AUTH_URL = "/wx/anon/webAuthOfUserInfo.jhtml";

    /**
     * 微信网页授权地址【静默授权地址】
     */
    public static final String BASE_WX_AUTH_URL = "/wx/anon/webAuthOfBase.jhtml";

    /**
     * 本系统微信首页地址【默认网页授权后跳转的地址】
     */
    public static final String SYSTEM_WX_INDEX_URL = "/wx/login/mbr/index.jhtml";

    /**
     * 本系统文章地址【默认的自定义文章展示地址】
     */
    public static final String SYSTEM_WX_ARTICLE_URL = "/wx/anon/wxArticle/getImgText.jhtml";

    /**
     * 获取token的url
     */
    public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    /**
     * 获取关注用户的用户信息【普通用户信息接口】
     */
    public static final String GET_SUBSCRIBE_USERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";

    /**
     * 网页授权url【scope=snsapi_userinfo】
     */
    public static final String WEB_AUTH_URL_USERINFO = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    /**
     * 网页授权url【scope=snsapi_base】
     */
    public static final String WEB_AUTH_URL_BASE = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";

    /**
     * 获取网页授权access_token的url
     */
    public static final String WEB_AUTH_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";

    /**
     * 获取用户信息【网页授权】
     */
    public static final String GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

    /**
     * 创建自定义菜单的url
     */
    public static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

    /**
     * 获取jsApiTicket的url
     */
    public static final String JS_API_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";

    /**
     * 根据模板shortId获取模板id
     */
    public static final String GET_TEMPLATE_ID_URL = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=ACCESS_TOKEN";

    /**
     * 发送模板消息url
     */
    public static final String SEND_TEMPLATEMESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";

    /**
     * 创建二维码url
     */
    public static final String CREATE_QR_CODE_URL = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=ACCESS_TOKEN";

    /**
     * 二维码图片路径
     */
    public static final String QR_CODE_IMAGE_URL = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET";

    /**
     * 获取临时多媒体文件
     */
    public static final String GET_MEDIA_URL = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";

    /**
     * 微信登录回调地址
     */
    public static final String WX_LOGIN_CALLBACK_URL = "/site/anon/wxLoginCallback.jhtml";

    /**
     * 微信登录--网站注册地址
     */
    public static final String WX_LOGIN_REGISTER_URL = "/site/anon/siteLogin/toReg.jhtml";

    /**
     * 微信登录---网站首页地址
     */
    public static final String WX_LOGIN_INDEX_URL = "/site/anon/index/index.jhtml";

    /**
     * 客服接口-发消息
     */
    public static final String WX_CUSTOM_SEND_MESSAGE = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";

    /**
     * 获取单例RedisClient客户端单例对象
     *
     * @return
     */
    private static RedisClient getRedisClient() {
        if (REDIS_CLIENT == null) {
            synchronized (WeChatUtil.class) {
                if (REDIS_CLIENT == null) {
                    REDIS_CLIENT = SpringUtils.getBean("redisClient", RedisClient.class);
                }
            }
        }
        return REDIS_CLIENT;
    }

    /**
     * 获取调用微信接口普通AccessToken
     *
     * @return 微信token
     */
    public static String getAccessToken() {
        return getAccessToken(1);
    }

    /**
     * 并发获取AccessToken
     *
     * @param tryCount 尝试调用次数【最大三次】
     * @return
     */
    public static String getAccessToken(int tryCount) {

        // 获取AccessToken
        AccessToken accessToken = (AccessToken) getRedisClient().get(RedisConsts.WX_PUBLIC_ACCESSTOKEN);
        try {
            if (accessToken == null) {
                long lock = getRedisClient().setnx(RedisConsts.WX_PUBLIC_ACCESSTOKENLOCK, RedisConsts.WX_PUBLIC_ACCESSTOKENLOCK);
                if (lock > 0) {
                    //获取到锁同时获取到accessToken后不立即返回，accessToken可能为空
                    log.info("准备从微信获取accessToken");

                    //防止死锁
                    getRedisClient().expireString(RedisConsts.WX_PUBLIC_ACCESSTOKENLOCK, 5);
                    accessToken = getAccessTokenByApi();

                    //删除锁
                    getRedisClient().delStrings(RedisConsts.WX_PUBLIC_ACCESSTOKENLOCK);
                } else if (lock < 1 && tryCount < 3) {
                    //未获取到锁，则等待，然后重试
                    Thread.sleep(500L);
                    return getAccessToken(tryCount++);
                } else {
                    //重试3次后仍未获取到锁，直接返回null
                    return null;
                }
            }
        } catch (Exception e) {
            log.error("\r\n ***********获取accessToken出错：{}", ExceptionUtils.getFullStackTrace(e));
        }
        return accessToken == null ? null : accessToken.getToken();
    }

    /**
     * 通过微信接口获取access_token
     *
     * @return
     */
    private static AccessToken getAccessTokenByApi() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("grant_type", "client_credential");
        map.put("appid", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_APPID));
        map.put("secret", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_APPSECRET));

        //GET方式获取Accesstoken
        JSONObject accessTokenObj = HttpUtil.getJSONObjectFromHttpsGet(ACCESS_TOKEN_URL, map);
        if (accessTokenObj != null && accessTokenObj.containsKey("access_token")) {
            return initAccessToken(accessTokenObj);
        } else {
            //POST方式获取Accesstoken
            accessTokenObj = HttpUtil.getJSONObjectFromHttpsPost(ACCESS_TOKEN_URL, map);
            if (accessTokenObj != null && accessTokenObj.containsKey("access_token")) {
                return initAccessToken(accessTokenObj);
            }
        }
        return null;
    }

    /**
     * 构建AccessToken，并且放入redis缓存
     *
     * @param accessTokenObj accessToken接口返回数据
     * @return
     */
    private static AccessToken initAccessToken(JSONObject accessTokenObj) {
        //构建AccessToken
        AccessToken accessToken = new AccessToken(accessTokenObj.getString("access_token"), accessTokenObj.getInt("expires_in"));

        //将AccessToken放入redis缓存
        getRedisClient().setAndExpire(RedisConsts.WX_PUBLIC_ACCESSTOKEN, accessToken, accessToken.getExpireIn());
        return accessToken;
    }

    /**
     * 获取JS接口的临时票据 JsApiTicket
     *
     * @return JsApiTicket
     */
    public static String getJsApiTicket() {
        return getJsApiTicket(1);
    }

    /**
     * 并发获取JS接口的临时票据  JsApiTicket
     *
     * @param tryCount 请求次数【最大三次】
     * @return JsApiTicket
     */
    public static String getJsApiTicket(int tryCount) {
        // 从缓存中获取JS接口临时票据
        AccessToken jsTicket = (AccessToken) getRedisClient().get(RedisConsts.WX_PUBLIC_JSTICKET);
        try {
            if (jsTicket == null) {
                long lock = getRedisClient().setnx(RedisConsts.WX_PUBLIC_JSTICKETLOCK, RedisConsts.WX_PUBLIC_JSTICKETLOCK);
                if (lock > 0) {
                    //获取到锁同时获取到jsTicket后不立即返回，jsTicket可能为空
                    log.info("准备从微信获取JsApiTicket");
                    //防止死锁
                    getRedisClient().expireString(RedisConsts.WX_PUBLIC_JSTICKETLOCK, 5);
                    jsTicket = getJsApiTicketByApi();
                    //删除锁
                    getRedisClient().delStrings(RedisConsts.WX_PUBLIC_JSTICKETLOCK);
                } else if (lock < 1 && tryCount < 3) {
                    //未获取到锁，则等待，然后重试
                    Thread.sleep(500L);
                    return getJsApiTicket(tryCount++);
                } else {
                    //重试3次后仍未获取到锁，直接返回null
                    return null;
                }
            }
        } catch (Exception e) {
            log.error("获取jsTicket出错：{}", ExceptionUtils.getFullStackTrace(e));
        }
        return jsTicket == null ? null : jsTicket.getToken();
    }

    /**
     * 调用微信接口获取 JsApiTicket
     *
     * @return AccessToken对象
     */
    private static AccessToken getJsApiTicketByApi() {
        // 调用微信接口，获取JSApiTicket
        String s = HttpUtil.httpsGet(JS_API_TICKET_URL.replace("ACCESS_TOKEN", getAccessToken()), new HashMap<String, Object>(), "UTF-8");
        JSONObject obj = JSONObject.fromObject(s);

        // 调用出错
        if (obj != null && "0".equals(obj.getString("errcode"))) {
            AccessToken jsAipTicket = new AccessToken(obj.getString("ticket"), obj.getInt("expires_in"));
            getRedisClient().setAndExpire(RedisConsts.WX_PUBLIC_JSTICKET, jsAipTicket, jsAipTicket.getExpireIn());
            return jsAipTicket;
        }
        return null;
    }

    /**
     * 获取网页授权URL
     *
     * @param state       网页授权参数
     * @param redirectUrl 网页授权后访问地址
     * @return 授权访问地址
     */
    public static String getWebAuthUrlOfUserInfo(String state, String redirectUrl) {
        try {
            String webAuthURL = WEB_AUTH_URL_USERINFO.replace("APPID", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_APPID)).replace("REDIRECT_URI", URLEncoder.encode(PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_DOMAIN) + redirectUrl, "UTF-8")).replace("STATE", state);
            return webAuthURL;
        } catch (UnsupportedEncodingException e) {
            log.error("用户信息网页授权URL出错：" + ExceptionUtils.getFullStackTrace(e));
        }
        return null;
    }

    /**
     * 获取网页授权URL
     *
     * @param state       网页授权参数
     * @param redirectUrl 网页授权后访问地址
     * @return 授权访问地址
     */
    public static String getWebAuthUrlOfBase(String state, String redirectUrl) {
        try {
            String webAuthURL = WEB_AUTH_URL_BASE.replace("APPID", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_APPID)).replace("REDIRECT_URI", URLEncoder.encode(PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_DOMAIN) + redirectUrl, "UTF-8")).replace("STATE", state);
            return webAuthURL;
        } catch (UnsupportedEncodingException e) {
            log.error("静默授权URL出错：" + ExceptionUtils.getFullStackTrace(e));
        }
        return null;
    }


    /**
     * 验证微信签名【验证服务器地址】
     *
     * @param wechat 验证对象
     * @return
     */
    public static boolean checkSign(WeChat wechat) {
        try {
            return WeChatSignUtil.checkSign(PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_TOKEN), wechat);
        } catch (Exception e) {
            log.error("验证微信签名出错：{}", ExceptionUtils.getFullStackTrace(e));
            return false;
        }

    }

    /**
     * 根据网页授权CODE换取AccessToken
     *
     * @param code 微信网页授权code
     * @return JSONObject
     */
    public static JSONObject getWebAuthAccessToken(String code) {
        // 初始化网页授权换取accessToken参数
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        map.put("appid", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_APPID));
        map.put("secret", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_APPSECRET));
        map.put("code", code);
        map.put("grant_type", "authorization_code");

        // 调用换取API
        JSONObject obj = HttpUtil.getJSONObjectFromHttpsPost(WEB_AUTH_ACCESS_TOKEN_URL, map);
        if (obj == null || obj.containsKey("errcode")) {
            log.error("调用【getWebAuthAccessToken】出错：{}", obj != null ? obj.toString() : "");
            throw new BaseCustomException("获取网页授权access_token发生错误!", obj.toString());
        }
        return obj;
    }

    /**
     * 获取关注用户的基本信息
     *
     * @param openId 用户OpenId
     * @return
     */
    public static JSONObject getSubScribeUserInfo(String openId) {
        // 调用微信用户信息
        JSONObject obj = HttpUtil.getJSONObjectFromHttpsPost(GET_SUBSCRIBE_USERINFO_URL.replace("ACCESS_TOKEN", getAccessToken()).replace("OPENID", openId), new HashMap<String, Object>());

        // 调用出错
        if (obj == null || obj.containsKey("errcode")) {
            log.error("调用【getSubScribeUserInfo】出错：{}", obj != null ? obj.toString() : "");
            throw new BaseCustomException("【getSubScribeUserInfo】", "获取关注用户信息出现错误！openid" + openId);
        }
        return obj;
    }

    /**
     * 获取用户信息
     *
     * @param accessToken 网页授权换取的access_token不同与基础支持的access_token
     * @param openid      用户的唯一标识
     * @return
     */
    public static JSONObject getUserInfo(String accessToken, String openid) {
        // 调用网页授权获取用户信息API
        JSONObject obj = HttpUtil.getJSONObjectFromHttpsPost(GET_USERINFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openid), new HashMap<String, Object>());
        if (obj == null || obj.containsKey("errcode")) {
            log.error("网页授权接口【getUserInfo】出错：{}", obj != null ? obj.toString() : "");
            throw new BaseCustomException("网页授权接口【getUserInfo】:", obj.toString());
        }
        return obj;
    }

    /**
     * 根据模板shortId获取模板id
     *
     * @return 模板id
     */
    public static String getTemplateId(String shortId) {
        // 判断shortId是否为空
        if (StringUtils.isEmpty(shortId)) {
            return null;
        }

        // 请求获取消息模板ID
        try {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("template_id_short", shortId);
            JSONObject result = HttpUtil.getJSONObjectFromHttpsPost(GET_TEMPLATE_ID_URL.replace("ACCESS_TOKEN", getAccessToken()), map);
            if (result != null) {
                if (!result.containsKey("template_id")) {
                    log.error("根据模板shortId获取template_id出错");
                    throw new BaseCustomException("getTemplateIdByShortIdError", result.getString("errcode") + ":" + result.getString("errmsg"));
                }
                return result.getString("template_id");
            }

        } catch (Exception e) {
            log.error("\r\n ************根据模板shortId获取模板id出错:{}", ExceptionUtils.getStackTrace(e));
        }
        return null;
    }

    /**
     * 发送模板消息
     *
     * @param message 模板消息对象
     */
    public static void sendTemplateMessage(TemplateMessage message) {
        try {
            if (message != null) {
                String postStr = JSONObject.fromObject(message).toString();
                HttpUtil.httpsPost(SEND_TEMPLATEMESSAGE_URL.replace("ACCESS_TOKEN", getAccessToken()), postStr);
            }
        } catch (Exception e) {
            log.error("\r\n ***********发送模板消息失败:{}", ExceptionUtils.getStackTrace(e));
        }

    }

    /**
     * 生成id值的临时二维码
     *
     * @param id 场景值
     * @return JSONObject
     */
    public static JSONObject createTempQRCode(long id) {
        try {
            TempQRCode qrCode = new TempQRCode(new IdScene(id));
            JSONObject result = HttpUtil.getJSONObjectFromHttpsPost(CREATE_QR_CODE_URL.replace("ACCESS_TOKEN", getAccessToken()), JSONObject.fromObject(qrCode).toString());

            if (result != null) {
                if (!result.containsKey("ticket")) {
                    throw new BaseCustomException("createTempQRCode", result.getString("errcode") + ":" + result.getString("errmsg"));
                }
                return result;
            }
        } catch (Exception e) {
            log.info("\r\n *********创建临时二维码出错:\r\n{}", ExceptionUtils.getStackTrace(e));
        }
        return null;
    }

    /**
     * 生成id值的永久二维码
     *
     * @param id 场景值
     * @return
     */
    public static JSONObject createLimitQRCode(long id) {
        try {
            LimitIDQRCode qrCode = new LimitIDQRCode(new IdScene(id));
            JSONObject result = HttpUtil.getJSONObjectFromHttpsPost(CREATE_QR_CODE_URL.replace("ACCESS_TOKEN", getAccessToken()), JSONObject.fromObject(qrCode).toString());
            if (result != null) {
                if (!result.containsKey("ticket")) {
                    throw new BaseCustomException("createTempQRCode", result.getString("errcode") + ":" + result.getString("errmsg"));
                }
                return result;
            }
        } catch (Exception e) {
            log.info("\r\n *********** 创建id值的永久二维码出错:{}", ExceptionUtils.getStackTrace(e));
        }
        return null;
    }

    /**
     * 生成Str值的临时二维码
     *
     * @param str 场景值
     * @return JSONObject
     */
    public static JSONObject createTempQRCode(String str) {
        try {
            TempQRCode qrCode = new TempQRCode(new StrScene(str));
            JSONObject result = HttpUtil.getJSONObjectFromHttpsPost(CREATE_QR_CODE_URL.replace("ACCESS_TOKEN", getAccessToken()), JSONObject.fromObject(qrCode).toString());

            if (result != null) {
                if (!result.containsKey("ticket")) {
                    throw new BaseCustomException("createTempQRCode", result.getString("errcode") + ":" + result.getString("errmsg"));
                }
                return result;
            }
        } catch (Exception e) {
            log.info("\r\n *********创建临时二维码出错:\r\n{}", ExceptionUtils.getStackTrace(e));
        }
        return null;
    }

    /**
     * 生成str值的永久二维码
     *
     * @param str
     * @return
     */
    public static JSONObject createLimitQRCode(String str) {
        try {
            LimitStrQRCode qrCode = new LimitStrQRCode(new StrScene(str));
            JSONObject result = HttpUtil.getJSONObjectFromHttpsPost(CREATE_QR_CODE_URL.replace("ACCESS_TOKEN", getAccessToken()), JSONObject.fromObject(qrCode).toString());

            if (result != null) {
                if (!result.containsKey("ticket")) {
                    throw new BaseCustomException("createTempQRCode", result.getString("errcode") + ":" + result.getString("errmsg"));
                }
                return result;
            }
        } catch (Exception e) {
            log.info("\r\n ***********创建永久二维码出错:{}", ExceptionUtils.getStackTrace(e));
        }

        return null;
    }

    /**
     * 根据临时媒体ID获取保存临时文件名称
     *
     * @param mediaId
     * @return
     */
    public static String getMeidaFileName(String mediaId) {

        log.debug("\r\n ************************ 保存临时多媒体文件START ************************* \r\n");
        //获取多媒体文件流
        InputStream inputStream = getMediaInputStream(mediaId, getAccessToken());

        //获取图片服务器磁盘挂载路径、临时文件名称
        String filePath = PropConfig.getProperty(PropAttributes.NFS__SERVICE_FILE_TEMP_PATH) + "/" + FilePathConsts.FILE_MEDIA_PATH;
        String fileName = System.currentTimeMillis() + ".jpg";
        File tempFile = new File(filePath.toString(), fileName);

        byte[] data = new byte[1024];
        int len = 0;
        FileOutputStream fileOutputStream = null;
        try {
            if (!tempFile.exists()) {
                tempFile.getParentFile().mkdirs();
                tempFile.createNewFile();
            }
            fileOutputStream = new FileOutputStream(tempFile);
            while ((len = inputStream.read(data)) != -1) {
                fileOutputStream.write(data, 0, len);
            }
            log.debug("\r\n ************************ 保存临时多媒体文件结束 ************************* \r\n");
        } catch (IOException e) {
            log.error("\r\n ***************** 创建临时文件出错 ************ \r\n");
            log.error(ExceptionUtils.getStackTrace(e));
            log.error("\r\n ***************** 创建临时文件出错 ************ \r\n");
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("\r\n ***************** 关闭输入流出错 ************ \r\n");
                    log.error(ExceptionUtils.getStackTrace(e));
                    log.error("\r\n *****************关闭输入流出错************ \r\n");
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    log.error("\r\n ***************** 关闭输出流出错 ************ \r\n");
                    log.error(ExceptionUtils.getStackTrace(e));
                    log.error("\r\n *****************关闭输出流出错************ \r\n");
                }
            }
        }

        log.debug("\r\n ************************ 保存临时多媒体文件END ************************* \r\n");
        return fileName;
    }

    /**
     * 根据微信token、媒体文件ID获取多媒体文件流
     *
     * @param mediaId
     * @param accessToken
     * @return
     */
    public static InputStream getMediaInputStream(String mediaId, String accessToken) {
        InputStream inputStream = null;
        try {
            String mediaUrl = WeChatUtil.GET_MEDIA_URL.replace("ACCESS_TOKEN", accessToken).replace("MEDIA_ID", mediaId);
            CloseableHttpClient httpsClient = HttpUtil.createSSLClientDefault();
            HttpGet get = new HttpGet(mediaUrl);
            HttpResponse response = httpsClient.execute(get);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                inputStream = response.getEntity().getContent();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (Exception e) {
            log.error("\r\n *************获取临时多媒体文件流出错*********************** \r\n");
            log.error(ExceptionUtils.getStackTrace(e));
            log.error("\r\n *************获取临时多媒体文件流出错*********************** \r\n");
        }
        return inputStream;
    }

    /**
     * 根据微信登录授权码获取accessToken
     *
     * @param code code
     * @return JSONObject
     */
    public static JSONObject getWxLoginAccessToken(String code) {
        // 初始化网页授权换取accessToken参数
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        map.put("appid", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_OPEN_LOGIN_APPID));
        map.put("secret", PropConfig.getProperty(PropAttributes.THIRDPARTY_WX_OPEN_LOGIN_APPSECRET));
        map.put("code", code);
        map.put("grant_type", "authorization_code");

        // 调用换取API
        JSONObject obj = HttpUtil.getJSONObjectFromHttpsPost(WEB_AUTH_ACCESS_TOKEN_URL, map);
        if (obj == null || obj.containsKey("errcode")) {
            log.error("获取微信登录access_token发生错误出错：{}", obj != null ? obj.toString() : "");
            throw new BaseCustomException("获取微信登录access_token发生错误!", obj.toString());
        }
        return obj;
    }

    /**
     * 客服接口-发消息
     *
     * @param message 需要发送的消息
     * @param openId  接收人的openId
     */
    public static void sendCustomMessage(String message, String openId) {
        // 初始化客服接口-发消息信息
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        map.put("touser", openId);
        map.put("msgtype", "text");
        // 发送的消息
        Map<String, Object> messageMap = new LinkedHashMap<>();
        messageMap.put("content", message);
        map.put("text", messageMap);

        // 将map转成String
        String result = null;
        try {
            result = JacksonUtil.toJsonStr(map);
        } catch (IOException e) {
            log.info("\r\n ***********客服接口发消息失败:{}", ExceptionUtils.getStackTrace(e));
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.SERVER_ERROR.getCode(), "客服接口发消息失败");
        }

        // 发送消息
        log.info("发送客服消息：{}", result);
        HttpUtil.httpsPost(WX_CUSTOM_SEND_MESSAGE.replace("ACCESS_TOKEN", getAccessToken()), result);
    }
}
